#include "Kernel.h"

#include "Views/MainMenuView.h"

KernelPtr Kernel::singleton;

KernelPtr Kernel::getSingleton()
{
	if(singleton == nullptr)
		singleton = std::make_shared<Kernel>();
	return singleton;
}

void Kernel::Shutdown()
{
	if(singleton)
	{
		long count = singleton.use_count();
		singleton.reset();
	}
}

Kernel::Kernel()
{
}

Kernel::~Kernel()
{
}

void Kernel::destroyContextUsers()
{
	exit();
}

void Kernel::config(const std::string &resource_dir)
{
	this->resource_dir = resource_dir;
}

bool Kernel::init(int argc, char** argv)
{
	glm::ivec2 fontsize((int)(128.0f/16.0f), (int)(128.0f/16.0f));
	glm::ivec2 viewport((int)(90.0f*(float)fontsize.x), (int)(60.0f*(float)fontsize.y));
	try{
		context = std::unique_ptr<GLContext>(new GLContext(viewport.x,viewport.y, false, "Trefall's Roguelike"));
	}catch(std::exception &e){
		std::cout << "Error: " << e.what() << std::endl;
		Kernel::Shutdown();
		return false;
	}
	context->setWindowCloseCallback([this](){this->destroyContextUsers();});
	context->setKeyCallback([this](int key, int pressed){this->keyInput(key,pressed);});
	context->setMouseButtonCallback([this](int button, int pressed){this->mouseButtonInput(button,pressed);});
	context->setMousePositionCallback([this](int x, int y){this->mouseMoveInput(x,y);});

	shader_loader = std::make_shared<File::ShaderLoader>(resource_dir + "Shaders/");
	tex_loader = std::make_shared<File::TextureLoader>(resource_dir + "Textures/");

	view_manager = std::unique_ptr<Views::ViewManager>(new Views::ViewManager(resource_dir));
	view_manager->add(new Views::MainMenuView(viewport, shader_loader, tex_loader));
	view_manager->pushActive("MAIN_MENU");

	return true;
}

void Kernel::run()
{
	previous_time = 0.0;
	running = true;

	while(running)
	{
		context->pollEvents();
		update(context->getTime());
		render();
		context->swapBuffers();
	}
	Kernel::Shutdown();
}

void Kernel::update(float time)
{
	double dt = time - previous_time;
	previous_time = time;

	view_manager->update((float)dt);
}

void Kernel::render()
{
	glClearColor(0.f,0.f,0.f,1.f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	view_manager->render();
}

void Kernel::reshape(int w, int h)
{
	glViewportIndexedf(0,0.0f, 0.0f, (float)w, (float)h);
}

void Kernel::keyInput(int key, int pressed)
{
	if(key == GLFW_KEY_ESCAPE)
		exit();
}

void Kernel::mouseButtonInput(int button, int pressed)
{
}

void Kernel::mouseMoveInput(int x, int y)
{
}
